﻿using FluentValidation;
using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.WebUtilities;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace Quickly.Identity.Services;

public class UserRegistration
{
    private static readonly EmailAddressAttribute _emailAddressAttribute = new();
    public record UserData(string UserName, string Email, string Password, string RepeatPassword);

    public record UserRegistrationCommand(UserData User) : IRequest<IdentityResult>;

    public class UserRegistrationCommandValidator : AbstractValidator<UserRegistrationCommand>
    {
        public UserRegistrationCommandValidator()
        {

            RuleFor(x => x.User)
                    .NotNull()
                    .ChildRules(
                        v =>
                        {
                            v.RuleFor(u => u.UserName).NotNull().NotEmpty();
                            v.RuleFor(u => u.Email).NotNull().NotEmpty();
                            v.RuleFor(u => u.Password).NotNull().NotEmpty();
                            v.RuleFor(u => u.RepeatPassword).Equal(u => u.Password).WithMessage("两次输入的密码不一样");
                        });
        }
    }

    public class UserRegistrationCommandHandler<TUser>(UserManager<TUser> userManager
        , IUserStore<TUser> userStore
        , IEmailSender<TUser> emailSender) 
        : IRequestHandler<UserRegistrationCommand, IdentityResult>
        where TUser : AppUser
    {
        public async Task<IdentityResult> Handle(UserRegistrationCommand request, CancellationToken cancellationToken)
        {
            var user = CreateUser();
            await userStore.SetUserNameAsync(user, request.User.UserName, cancellationToken);
            var emailStore = GetEmailStore();
            await emailStore.SetEmailAsync(user, request.User.Email, cancellationToken);
            var result = await userManager.CreateAsync(user, request.User.Password);

            if(result.Succeeded == false)
            {
                return result;
            }

            var userId = await userManager.GetUserIdAsync(user);
            var code = await userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));

            // todo: email confirmation callback url
            var callbackUrl = string.Empty;
            
            await emailSender.SendConfirmationLinkAsync(user, request.User.Email, callbackUrl);

            if(userManager.Options.SignIn.RequireConfirmedAccount)
            {
                // todo: next-step redirect to register confirmation
            }

            // todo: next-step redirect to login

            return result;
        }

        private TUser CreateUser()
        {
            return Activator.CreateInstance<TUser>();
        }

        private IUserEmailStore<TUser> GetEmailStore()
        {
            if (!userManager.SupportsUserEmail)
            {
                throw new NotSupportedException("The default UI requires a user store with email support.");
            }
            return (IUserEmailStore<TUser>)userStore;
        }
    }
}
